package com.dodayum.service;

import cn.hutool.core.date.DateUtil;
import com.dodayum.dto.NginxLogInfoRequestDTO;
import com.dodayum.dto.SearchByResponseDTO;
import com.dodayum.dto.SuccessUrlTop10Response;
import com.dodayum.entity.NginxLogInfo;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ValueCountAggregationBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

import static org.elasticsearch.index.query.QueryBuilders.*;

/**
 * @version 1.0
 * 备注：
 * @Author BaiYu
 * </br>@Date 2024/12/27 11:39
 */

@Service
public class MyEntityHardService {

    @Resource
    ElasticsearchOperations elasticsearchOperations;
    @Resource
    ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 按天，进行显示当天的ip地址、请求地址、请求状态，并且分页+支持模糊查询
     *
     * @param request {@link NginxLogInfoRequestDTO}查询条件
     * @return {@link List<SearchByResponseDTO>}
     */
    public List<SearchByResponseDTO> searchByRequest(NginxLogInfoRequestDTO request) {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        Date beginOfDay = DateUtil.beginOfDay(request.getRequestTime()).toJdkDate();
        Date endOfDay = DateUtil.endOfDay(request.getRequestTime()).toJdkDate();
        boolQueryBuilder.must(rangeQuery("requestTime").gte(beginOfDay.getTime()).lte(endOfDay.getTime()));


        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        // query查询
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        // 分页
        nativeSearchQueryBuilder.withPageable(PageRequest.of(request.getPageNum() - 1, request.getPageSize()));
        // 只显示某些字段x
        nativeSearchQueryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"requestIp", "requestUrl", "success", "requestTime"}, null));
        nativeSearchQueryBuilder.withSorts(SortBuilders.fieldSort("requestTime").order(SortOrder.DESC));

        Query query = nativeSearchQueryBuilder.build();
        SearchHits<NginxLogInfo> searchHits = elasticsearchOperations.search(query, NginxLogInfo.class);
        List<SearchHit<NginxLogInfo>> queryResponse = searchHits.getSearchHits();
        List<SearchByResponseDTO> response = new ArrayList<>();
        for (SearchHit<NginxLogInfo> myEntitySearchHit : queryResponse) {
            NginxLogInfo content = myEntitySearchHit.getContent();
            SearchByResponseDTO responseData = new SearchByResponseDTO();
            BeanUtils.copyProperties(content, responseData);
            response.add(responseData);
        }
        return response;
    }

    /**
     * 成功访问URL地址top10
     *
     * @return {@link List<SuccessUrlTop10Response>}
     */
    public List<SuccessUrlTop10Response> successUrlTop10() {
        // 查询条件
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.must(termQuery("success", Boolean.TRUE));

        // 聚合
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("requestUrlAgg").field("requestUrl.keyword").size(10);
        ValueCountAggregationBuilder countAggregationBuilder = AggregationBuilders.count("count").field("requestUrl.keyword");
        termsAggregationBuilder.subAggregation(countAggregationBuilder);

        // 构建查询json
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        nativeSearchQueryBuilder.withAggregations(termsAggregationBuilder);
        NativeSearchQuery build = nativeSearchQueryBuilder.build();

        SearchHits<NginxLogInfo> search = elasticsearchRestTemplate.search(build, NginxLogInfo.class);
        AggregationsContainer<Aggregations> aggregationsContainer = (AggregationsContainer<Aggregations>) search.getAggregations();
        Aggregations aggregations = aggregationsContainer.aggregations();
        Map<String, Aggregation> map = aggregations.asMap();
        Aggregation aggregation = map.get("requestUrlAgg");
        Terms termsAgg = (Terms) aggregation;
        List<SuccessUrlTop10Response> response = new ArrayList<>();
        for (Terms.Bucket bucket : termsAgg.getBuckets()) {
            response.add(new SuccessUrlTop10Response(bucket.getKeyAsString(), bucket.getDocCount()));
        }

        return response;
    }

    /**
     * 访问失败的IP地址top5
     *
     * @return {@link Map}
     */
    public Map<String, String> falseIpTop10() {

        // 查询条件
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.must(termQuery("success", Boolean.FALSE));

        // 聚合
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("requestIpAgg").field("requestIp.keyword").size(5);
        ValueCountAggregationBuilder countAggregationBuilder = AggregationBuilders.count("count").field("requestIp.keyword");
        termsAggregationBuilder.subAggregation(countAggregationBuilder);

        // 构建查询json
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        nativeSearchQueryBuilder.withAggregations(termsAggregationBuilder);
        NativeSearchQuery build = nativeSearchQueryBuilder.build();

        SearchHits<NginxLogInfo> search = elasticsearchRestTemplate.search(build, NginxLogInfo.class);
        AggregationsContainer<Aggregations> aggregations = (AggregationsContainer<Aggregations>) search.getAggregations();
        Aggregations aggregations1 = aggregations.aggregations();

        Map<String, Aggregation> map = aggregations1.asMap();
        Aggregation aggregation = map.get("requestIpAgg");
        Terms termsAgg = (Terms) aggregation;
        Map<String, String> response = new HashMap<>();
        termsAgg.getBuckets().forEach(bucket -> {
            response.put(bucket.getKeyAsString(), String.valueOf(bucket.getDocCount()));
        });

        return response;
    }
}
